use std::{borrow::Cow, fmt::Display};

use axum::extract::rejection::BytesRejection;
use serde::Serialize;
use thiserror::Error;

pub type IoErr = std::io::Error;
pub type CborErr = serde_cbor::Error;
pub type SqlxErr = sqlx::Error;

#[derive(Debug, Error)]
pub enum AppErr {

    #[error("io:{0}")]
    Io(#[from] IoErr),

    #[error("cbor:{0}")]
    Cbor(#[from] CborErr),

    #[error("sqlx:{0}")]
    Sqlx(#[from] SqlxErr),

    #[error("{0}")]
    Custom(#[from] ErrInfo),

    #[error("bytes:{0}")]
    Bytes(#[from] BytesRejection),

    #[error("wrap:{0}")]
    Wrap(String),
}

#[derive(Debug, Error, Serialize)]
pub struct ErrInfo {
    pub err_code: i32,
    pub err_msg: Cow<'static, str>,
}

impl Display for ErrInfo {

    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "err:{} => {}", self.err_code, self.err_msg)
    }
}

pub fn new_err_msg(ec: i32, msg: &'static str) -> AppErr {
    AppErr::Custom(ErrInfo { err_code: ec, err_msg: Cow::Borrowed(msg) })
}

pub mod ec {
    pub const OK: i32 = 0;
    
    // 设备已经存在
    pub const DEVICE_EXISTS: i32 = 1;
    pub const DEVICE_EXISTS_MSG: &'static str = "该设备已经存在";

    pub const DEVICE_NOT_EXISTS: i32 = 2;
    pub const DEVICE_NOT_EXISTS_MSG: &'static str = "该设备不存在";

    pub const IPC_EXISTS: i32 = 3;
    pub const IPC_EXISTS_MSG: &'static str = "该IPC存在已经存在";

    pub const IPC_NOT_EXISTS: i32 = 4;
    pub const IPC_NOT_EXISTS_MSG: &'static str = "该IPC不存在";

    pub const DEVICE_NO_TOKEN: i32 = 5;
    pub const DEVICE_NO_TOKEN_MSG: &'static str = "no token";

    pub const SEND_MSG_TIMEOUT: i32 = 7;
    pub const SEND_MSG_TIMEOUT_MSG: &'static str = "发送消息超时";

    pub const POLL_MSG_TIMEOUT: i32 = 8;
    pub const POLL_MSG_TIMEOUT_MSG: &'static str = "接收消息超时";

    pub const FIRM_NOT_EXISTS: i32 = 9;
    pub const FIRM_NOT_EXISTS_MSG: &'static str = "固件不存在";

    pub const ADV_NOT_EXISTS: i32 = 10;
    pub const ADV_NOT_EXISTS_MSG: &'static str = "广告不存在";

    pub const PRODUCT_IS_EXISTS: i32 = 11;
    pub const PRODUCT_IS_EXISTS_MSG: &'static str = "商品名称重复";

    pub const FIRM_IS_EXISTS: i32 = 12;
    pub const FIRM_IS_EXISTS_MSG: &'static str = "固件版本重复";

    pub const ADV_IS_EXISTS: i32 = 13;
    pub const ADV_IS_EXISTS_MSG: &'static str = "广告名称重复";

    pub const ADV_SET_IS_EXISTS: i32 = 14;
    pub const ADV_SET_IS_EXISTS_MSG: &'static str = "广告设置重复";

    pub const DEVICE_IS_NOT_LOGIN: i32 = 15;
    pub const DEVICE_IS_NOT_LOGIN_MSG: &'static str = "该设备没有登陆";

    pub const MSG_REQ_HEAD_INVALID: i32 = 16;

    pub const MSG_NO_RECV: i32 = 17;

    pub const MSG_NO_ACK: i32 = 18;
    pub const MSG_NO_PONG: i32 = 19;
    pub const MSG_NO_RESP: i32 = 20;
}

pub trait ErrorWrap<T> {
    
    fn wrap(self) -> Result<T, AppErr>;
}

impl <T, E: std::error::Error> ErrorWrap<T> for Result<T, E> {

    fn wrap(self) -> Result<T, AppErr> {
        match self {
            Ok(v) => Ok(v),
            Err(e) => Err(AppErr::Wrap(e.to_string()))
        }
    }

}

impl <T> ErrorWrap<T> for Option<T> {

    fn wrap(self) -> Result<T, AppErr> {
        match self {
            Some(v) => Ok(v),
            None => Err(AppErr::Wrap(String::from("option is none")))
        }
    }
}

